Kotlin multithreading: Comparing .wait(), .sleep(), and .delay()

您所在的位置:网站首页 runblocking in kotlin coroutines with example Kotlin multithreading: Comparing .wait(), .sleep(), and .delay()

Kotlin multithreading: Comparing .wait(), .sleep(), and .delay()

2023-09-01 01:28| 来源: 网络整理| 查看: 265

Ivan Garza Follow Ivan is an Android engineer at Mixhalo, a passionate fútbol fan, and an amateur salsa maker. Kotlin multithreading: Comparing .wait(), .sleep(), and .delay()

April 12, 2023 5 min read 1410 110

Using Kotlin Sleep(), Delay(), And Wait() In Your Android App

Multithreading programming is one of those taboo subjects that not many developers enjoy talking about. The complexity of the topic has driven away even experienced programmers for as long as it has been helping us solve problems.

This had been particularly true for the Android platform, especially back when we were predominantly using Java. Between the juggling of different threads, its Handlers and Runners, there was little time for sanity. And let’s not mention the memory leaks.

When the Android OS was introduced to the world of coroutines by the new programming language Kotlin, everything changed. The practice of multithreading programming stopped feeling as intimidating or foreign as it did before. Kotlin and its coroutines allowed for developers to write multithreading code in a cleaner and more efficient way. Check out this article to learn more information on what Kotlin coroutines are and how to use them.

Kotlin coroutines introduced a new set of keywords and APIs that made multithreading patterns easier to read and ultimately understand. Keywords such as suspend and runBlocking allow for a more human-readable way of understanding what these multithreading APIs do, and allow devs to better establish their expectations. For a deeper explanation on the two keywords mentioned above and their usage, check out this article.

In this article, I will explore three individual functions that are commonly used in multithreading programming while working in Kotlin: wait(), sleep(), and delay(). As you may have noticed, not all of these three functions actually belong to the Kotlin programming language, but instead we’ll approach this inquiry into the particularities of the multithreading paradigm from a broader perspective.

Jump ahead:

.wait() .sleep() .delay() Comparing .sleep(), .wait(), and .delay() Wait

Let’s start from the very bottom. The .wait() function pertains to the the low-level Object class not from Kotlin, but from the Java programming language. Object#wait() is meant to be called onto any kind of object in order to instruct the running thread to wait indefinitely. As the Java official documentation illustrates, calling .wait() behaves the same way as the call wait(0), or it causes the current thread to wait until another thread calls .notify() or .notifyAll() on the same object.

Let’s elaborate further with a simple example. Assume we have the object obj in our running working thread thread1, and we call wait() on it:

// thread1 obj.wait()

This would effectively sleep the thread until it is either notified, as it was explained above, or otherwise interrupted. In order to notify thread1 to continue execution from thread2, we would call the notify() function on the same obj instance:

// thread2 obj.notify()

This pattern is particularly useful when we want a thread to wait when hitting a specific part of the code. The object to which we wait — in our example above, the obj variable — serves as a lock that conducts the thread’s execution through a timeout that may only be lifted by another thread’s action.

In other words, thread1 will be blocked and allow for asynchronous execution of other thread(s) — in our example above, we only run thread2 simultaneously — until thread1 is allowed to continue its execution.

Let’s go over one more example, which we’ll use to illustrate the differences of this function with respect to our other two protagonists:

import java.util.concurrent.TimeUnit import kotlin.test.* import kotlinx.coroutines.* val scope = CoroutineScope(Dispatchers.Default) val lock = Object() fun main() { println("We're testing .wait()!") runBlocking(Dispatchers.Default) { launch(Dispatchers.IO) { testWaitThread2() } testWaitThread1() } } fun testWaitThread1() = synchronized(lock) { lock.wait() println("Print second") } fun testWaitThread2() = synchronized(lock) { println("Print first") lock.notify() } Sleep

There are two different sleep functions available to the Kotlin programming language: Thread#sleep() and TimeUnit#sleep(). Both of these functions essentially perform the same thing, as TimeUnit#sleep() will call Thread#sleep() as part of its execution. Therefore, both of these methods will sleep a thread, or cease its execution temporarily, by the specified amount of time.

The main difference between these options is that the TimeUnit equivalent of the sleep function will first verify that the unit received is positive, and only call Thread#sleep() after that is cleared out. This means that the TimeUnit version of the sleep function is safer to use because it will not throw an IllegalArgumentException, as the Thread version of the function will do with negative numbers.

The second advantage of the TimeUnit implementation of sleep is how much more readable it is. The following example will show usage of both kinds of sleep functions, and it will demonstrate how the Thread equivalent of it can become very hard to read too easily:

// 1 second Thread.sleep(1000) TimeUnit.SECONDS.sleep(1) // 120 seconds Thread.sleep(120000) TimeUnit.SECONDS.sleep(120) // 1 minute Thread.sleep(60000) TimeUnit.MINUTES.sleep(1) // 19 minute Thread.sleep(540000) TimeUnit.MINUTES.sleep(19) // 1 hour Thread.sleep(3600000) TimeUnit.HOURS.sleep(1)

Because both of these functions do the same and send the thread to sleep, we find a useful tool for asynchronous programming for whenever we want to control the order of operations. For example, the following program will demonstrate how creating two different threads and calling sleep on them simultaneously, we can control who goes first based on the duration of their sleep functions:

import java.util.concurrent.TimeUnit import kotlin.test.* import kotlinx.coroutines.* val scope = CoroutineScope(Dispatchers.Default) fun main() { println("We're testing .sleep()!") runBlocking(Dispatchers.Default) { launch { testSleepThread() } launch { testSleepTimeUnit() } } } suspend fun testSleepThread() { Thread.sleep(5000) // 5000 ms = 5 seconds println("Print second") } suspend fun testSleepTimeUnit() { TimeUnit.SECONDS.sleep(3) println("Print first") } Delay

Last but not least, .delay() is the only function from today’s cast that belongs to the Kotlin programming language. Differently from the last two protagonists, delay() can only be called from inside a coroutine.

This function delays the given coroutine for a given time without blocking a thread, as the Kotlin official documentation explains, and it resumes after a specified time in the function parameter. This suspending function is cancellable, which means that we can ask the coroutine to continue execution at any point in time.

From the perspective of asynchronous design, the delay function behaves very much the same as either of the sleep functions, as it halts the execution of the given component of concurrent programming for a predefined amount of time.

We’ll use one last example to demonstrate the similarities between the delay() function and the predeceasing sleep() functions with a slight modification. Notice that we arrive at the exact same conclusion, with almost the exact same code:

import java.util.concurrent.TimeUnit import kotlin.test.* import kotlinx.coroutines.* val scope = CoroutineScope(Dispatchers.Default) val lock = Object() fun main() { println("We're testing .delay()!") runBlocking(Dispatchers.Default) { launch { testDelayThread2() } launch { testDelayThread1() } } } suspend fun testDelayThread1() { delay(5000) println("Print second") } suspend fun testDelayThread2() { delay(3000) println("Print first") } Comparing .sleep(), .wait(), and .delay()

Now that we’ve explored each one of the main functions of this inquiry, let’s switch gears and analyze the main differences and similarities between each of them.

Evidently, the first thing that stands out is the similarity between sleep and delay. Both of these functions halt the running thread or coroutine for a given amount of time. Also, in their simplest forms, both of these functions accept a single parameter that specifies the duration of the given execution freeze, and both of them take that parameter in milliseconds.

Nevertheless, and as it has been mentioned before, the sleep function exclusively applies to threads, while the delay function instead freezes the execution of a coroutine, which does not guarantee whether the thread will be blocked or not.

Over 200k developers use LogRocket to create better digital experiences Learn more →

Moreover, it is obvious that the wait function stands on different grounds. It uses an object as a locking mechanism, where the calling thread does not continue execution until it is given the signal to do so. This means that while their counter options halt execution for a finite and defined amount of time, the wait function may keep the thread locked, or frozen, for an indefinite time.

Conclusion

The introduction of the Kotlin coroutines into the multithreading world of Java added both an extra layer of complications and a brand new set of solutions. Today we’ve explored a small corner of the product of that through the .wait(), sleep(), and .delay() functions.

We’ve seen how these functions can be used to control the flow and order of execution of different streams of information, and how this can be advantageous when dealing with multithreading and asynchronous programming alike.

LogRocket: Instantly recreate issues in your Android apps.

LogRocket is an Android monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your Android apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your Android apps — try LogRocket for free.

Share this:TwitterRedditLinkedInFacebook Ivan Garza Follow Ivan is an Android engineer at Mixhalo, a passionate fútbol fan, and an amateur salsa maker. Featured Posts Uncategorized #kotlin « 8 Figma plugins for design system management What is penetration pricing? Definition and pricing strategy examples »


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3